import { Vector3 } from 'babylon-lib/index';
import { ICommunityData } from '../../data/community';
import { BLOC_INFOS, IBlocInfo, PLAYER_BLOC } from '../../global/global-constant';
import { CommunityData } from '../community/community-data';
import { Random } from 'babylon-lib/tool/random';
import { MAX_NONE_PLAYER_COMMUNITY } from '../../data/data';


/**
 * 分配建筑主权
 */
class SetupPartition {

    // 固定势力
    private static _fixedBloc: IBlocInfo[] = [];
    // 未被选择的玩家势力
    private static _unselectedBloc: IBlocInfo[] = [];
    // 被选择的玩家势力
    private static _selectedBloc: IBlocInfo[] = [];
    // 已分配主权的建筑
    private static _distributed: string[] = [];

    /**
     * 非玩家势力（含固定势力和未被玩家选择的势力）
     */
    public static get botBloc(): IBlocInfo[] {
        return [...this._unselectedBloc, ...this._fixedBloc];
    }

    /**
     * 玩家势力（含当前用户选择的势力和其他玩家选择的势力）
     */
    public static get playerBloc(): IBlocInfo[] {
        return [...this._selectedBloc];
    }

    /**
     * 分配所有建筑的初始主权
     * @param playerBlocs 玩家选择的势力
     */
    public static setup(playerBlocs: PLAYER_BLOC[]): void {
        for (const info of BLOC_INFOS) {
            if (Object.values(PLAYER_BLOC).includes(info.name as PLAYER_BLOC)) {
                if (playerBlocs.includes(info.name as PLAYER_BLOC)) {
                    this._selectedBloc.push(info);
                } else {
                    this._unselectedBloc.push(info);
                }
            } else {
                this._fixedBloc.push(info);
            }
        }

        this.distributeFixedBloc();
        this.distributeUnselectedBloc();
        this.distributeSelectedBloc();
    }

    private static signCommunity(community: ICommunityData, bloc: string): void {
        community.sovereign = bloc;
        this._distributed.push(community.rawName);
    }

    private static trySignVillageSovereign(bloc: string, village: ICommunityData, refCommunities: ICommunityData[]): boolean {
        let minIdx = -1;
        let minDistance = Number.MAX_VALUE;
        for (let i = 0; i < refCommunities.length; i++) {
            const ref = refCommunities[i];
            const ds = Vector3.DistanceSquared(ref.location, village.location);
            if (ds < minDistance) {
                minDistance = ds;
                minIdx = i;
            }
        }
        const ref = refCommunities[minIdx];
        if (!ref) return false;
        if (ref.sovereign != bloc) return false;
        this.signCommunity(village, bloc);
        return true;
    }

    /**
     * 为固定势力分配建筑
     * 城、镇、关使用固定数据，仅通过算法分配邑
     */
    private static distributeFixedBloc(): void {
        const sovereignC = [...CommunityData.cityData, ...CommunityData.townData, ...CommunityData.fortressData];
        for (const bloc of this._fixedBloc) {
            for (const community of sovereignC) {
                if (community.sovereign === bloc.name) {
                    this.signCommunity(community, bloc.name);
                }
            }
            for (const community of CommunityData.villageData) {
                this.trySignVillageSovereign(bloc.name, community, sovereignC);
            }
        }
    }

    /**
     * 为未选择的势力分配建筑
     * 在预设主权建筑范围（城镇）内随机选取相邻建筑，数量不超过设定上限
     */
    private static distributeUnselectedBloc(): void {
        const sovereignC = [...CommunityData.cityData, ...CommunityData.townData, ...CommunityData.fortressData];
        const communities = [...CommunityData.cityData, ...CommunityData.townData]
        for (const bloc of this._unselectedBloc) {
            const preset = [];
            for (const community of communities) {
                if (community.sovereign === bloc.name) {
                    preset.push(community);
                }
            }

            const center = Random.selectFrom(preset, true);
            if (!center) continue;
            let count = Random.int(1, MAX_NONE_PLAYER_COMMUNITY) - 1;
            do {
                let minIdx = -1;
                let minDistance = Number.MAX_VALUE;
                for (let i = 0; i < preset.length; i++) {
                    const ds = Vector3.DistanceSquared(center.location, preset[i].location);
                    if (ds < minDistance) {
                        minDistance = ds;
                        minIdx = i;
                    }
                }
                if (minIdx >= 0) {
                    const community = preset[minIdx];
                    this.signCommunity(community, bloc.name);
                    preset.splice(minIdx, 1);
                }
                count--;
            } while (count > 0);
            preset.forEach((community) => { community.sovereign = undefined; });

            for (const community of CommunityData.villageData) {
                this.trySignVillageSovereign(bloc.name, community, sovereignC);
            }
        }
    }

    /**
     * 为玩家选择的势力分配建筑
     * 在预设主权建筑的基础上追加尚未分配的建筑
     */
    private static distributeSelectedBloc(): void {
        const sovereignC = [...CommunityData.cityData, ...CommunityData.townData, ...CommunityData.fortressData];
        let count = 0;
        for (const community of sovereignC) {
            let remain = true;
            for (const bloc of this._selectedBloc) {
                if (community.sovereign === bloc.name) {
                    this.signCommunity(community, bloc.name);
                    remain = false;
                    break;
                }
            }
            if (remain) count++;
        }

        const dta = count / this._selectedBloc.length;
        for (let i = 0; i < this._selectedBloc.length; i++) {
            const bloc = this._selectedBloc[i];
            if (i === this._selectedBloc.length - 1) {
                for (const sc of sovereignC) {
                    if (this._distributed.includes(sc.rawName)) continue;
                    this.signCommunity(sc, bloc.name);
                }
            } else {
                const bcs = [];
                for (const community of sovereignC) {
                    if (community.sovereign === bloc.name) {
                        bcs.push(community);
                    }
                }
                for (let j = 0; j < dta; j++) {
                    const ref = Random.selectFrom(bcs, false)!;
                    let minIdx = -1;
                    let minDistance = Number.MAX_VALUE;
                    for (let k = 0; k < sovereignC.length; k++) {
                        const sc = sovereignC[k];
                        if (this._distributed.includes(sc.rawName)) continue;
                        const ds = Vector3.DistanceSquared(ref.location, sc.location);
                        if (ds < minDistance) {
                            minDistance = ds;
                            minIdx = k;
                        }
                    }
                    if (minIdx >= 0) {
                        const community = sovereignC[minIdx];
                        this.signCommunity(community, bloc.name);
                        bcs.push(community);
                    }
                }
            }
        }

        for (const bloc of this._selectedBloc) {
            for (const community of CommunityData.villageData) {
                this.trySignVillageSovereign(bloc.name, community, sovereignC)
            }
        }
    }

}


export { SetupPartition };